﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using SD.LLBLGen.Pro.QuerySpec;
using SD.LLBLGen.Pro.QuerySpec.Adapter;
using VNet.VisiSuite.BusinessLogic.BusinessException;
using VNet.VisiSuite.Common.Helper;
using VNet.VisiSuite.Dal.DatabaseSpecific;
using VNet.VisiSuite.Dal.EntityClasses;
using VNet.VisiSuite.Dal.FactoryClasses;
using VNet.VisiSuite.Dal.HelperClasses;
using VNet.VisiSuite.Service.Contact.Message.Base;
using VNet.VisiSuite.Service.Contact.Message.Item;
using VNet.VisiSuite.Service.Contact.Message;
using VNet.VisiSuite.Service.Contact.Enum;
using VNet.VisiSuite.Common.Logger;
using SD.LLBLGen.Pro.ORMSupportClasses;


namespace VNet.VisiSuite.BusinessLogic
{
    public static class EnumerableExt
    {
        public static IEnumerable<IEnumerable<T>> Partition<T>(this IEnumerable<T> input, int blockSize)
        {
            var enumerator = input.GetEnumerator();

            while (enumerator.MoveNext())
            {
                yield return nextPartition(enumerator, blockSize);
            }
        }

        private static IEnumerable<T> nextPartition<T>(IEnumerator<T> enumerator, int blockSize)
        {
            do
            {
                yield return enumerator.Current;
            }
            while (--blockSize > 0 && enumerator.MoveNext());
        }
    }

    public class SyncUtil
    {

        public ConfigureResponse VerifyCellAndGetServerData(ConfigureRequest request)
        {
            #region Declaration
            var result = new ConfigureResponse() { Success = true, };
            var pass = request.CellId == 0 ? EncryptionHelper.EncodePassword(request.Password) : request.Password;
            var qf = new QueryFactory();
            var query = qf.Create()
                    .Select(() => new
                    {
                        //Cell
                        CellId = CellFields.CellId.Source("c").ToValue<int>(),
                        CellName = CellFields.CellName.Source("c").ToValue<string>(),
                        Operators = CellFields.Operators.Source("c").ToValue<short>(),
                        Assigned = CellFields.Assigned.Source("c").ToValue<bool>(),
                        CDescription = CellFields.Description.Source("c").SetFieldAlias("CDescription").ToValue<string>(),
                        CEnabled = CellFields.Enabled.Source("c").SetFieldAlias("CEnabled").ToValue<bool>(),
                        CTimeStamp = CellFields.TimeStamp.Source("c").SetFieldAlias("CTimeStamp").ToValue<byte[]>(),

                        //Area
                        AreaId = AreaFields.AreaId.Source("a").ToValue<int>(),
                        AreaName = AreaFields.AreaName.Source("a").ToValue<string>(),
                        ContinuousProcess = AreaFields.ContinuousProcess.Source("a").ToValue<bool>(),
                        GoodReasonCodeId = AreaFields.GoodReasonCodeId.Source("a").ToValue<int?>(),
                        ReworkReasonCodeId = AreaFields.ReworkReasonCodeId.Source("a").ToValue<int?>(),
                        ScrapReasonCodeId = AreaFields.ScrapReasonCodeId.Source("a").ToValue<int?>(),
                        ShiftStartReasonCodeId = AreaFields.ShiftStartReasonCodeId.Source("a").ToValue<int?>(),
                        CloseWorkOrderReasonCodeId = AreaFields.CloseWorkOrderReasonCodeId.Source("a").ToValue<int?>(),
                        NoWorkOrdersReasonCodeId = AreaFields.NoWorkOrdersReasonCodeId.Source("a").ToValue<int?>(),
                        WeekStartDay = AreaFields.WeekStartDay.Source("a").ToValue<int>(),
                        MonthStartDay = AreaFields.MonthStartDay.Source("a").ToValue<int>(),
                        ProductionMeterWidth = AreaFields.ProductionMeterWidth.Source("a").ToValue<int>(),
                        ProductionMeterLabelFreq = AreaFields.ProductionMeterLabelFreq.Source("a").ToValue<int>(),
                        PlannedReasonCodeId = AreaFields.PlannedReasonCodeId.Source("a").ToValue<int?>(),
                        ProductionGoal = AreaFields.ProductionGoal.Source("a").ToValue<int?>(),
                        ADescription = AreaFields.Description.Source("a").SetFieldAlias("ADescription").ToValue<string>(),
                        AEnabled = AreaFields.Enabled.Source("a").SetFieldAlias("AEnabled").ToValue<bool>(),
                        ATimeStamp = AreaFields.TimeStamp.Source("a").SetFieldAlias("ATimeStamp").ToValue<byte[]>(),

                        //Plant
                        PlantId = PlantFields.PlantId.Source("p").ToValue<int>(),
                        PlantName = PlantFields.PlantName.Source("p").ToValue<string>(),
                        PDescription = PlantFields.Description.Source("p").SetFieldAlias("PDescription").ToValue<string>(),
                        PDateFormat = PlantFields.DateFormat.Source("p").SetFieldAlias("PDateFormat").ToValue<string>(),
                        PEnabled = PlantFields.Enabled.Source("p").SetFieldAlias("PEnabled").ToValue<bool>(),
                        PTimeStamp = PlantFields.TimeStamp.Source("p").SetFieldAlias("PTimeStamp").ToValue<byte[]>(),

                    })
                    .From(qf.Area.As("c").InnerJoin(CellEntity.Relations.AreaEntityUsingAreaId, "c", "a")
                                                    .InnerJoin(AreaEntity.Relations.PlantEntityUsingPlantId, "a", "p")
                                                    )
                    .Where(CellFields.Password.Source("c") == pass
                         & CellFields.Enabled.Source("c") == true
                         & AreaFields.Enabled.Source("a") == true
                         & PlantFields.Enabled.Source("p") == true);
            #endregion

            using (var adapter = new DataAccessAdapter())
            {
                try
                {
                    adapter.StartTransaction(IsolationLevel.ReadCommitted, "ConfigureTransaction");

                    #region Get data from DB
                    var entity = adapter.FetchQuery(query).FirstOrDefault();

                    if (entity == null || (request.CellId != 0 && entity.CellId != request.CellId))
                        return new ConfigureResponse { Success = false, Error = BusinessLogicError.InvalidCellPassword, };

                    //Get Cell Entity to change Password
                    var cellEntity = new CellEntity { CellId = entity.CellId };
                    if (!adapter.FetchEntity(cellEntity))
                        return new ConfigureResponse { Success = false, Error = BusinessLogicError.ConfigureFailed, };

                    //Change to a random password 
                    var newPassword = pass;
                    if (request.CellId == 0)
                    {
                        var rand = new Random();
                        newPassword = EncryptionHelper.EncodePassword(rand.NextDouble().ToString());
                        cellEntity.Password = newPassword;
                        if (!adapter.SaveEntity(cellEntity))
                            return new ConfigureResponse { Success = false, Error = BusinessLogicError.ConfigureFailed, };
                        if (!adapter.FetchEntity(cellEntity))
                            return new ConfigureResponse { Success = false, Error = BusinessLogicError.ConfigureFailed, };
                    }

                    var tdc_qry = qf.TableDataChange
                        .Where(TableDataChangeFields.CellId == entity.CellId)
                        .OrWhere((TableDataChangeFields.CellId.IsNull()).And(TableDataChangeFields.AreaId == entity.AreaId));
                    var table_data_changes = adapter.FetchQuery(tdc_qry);

                    //CellAlarmSetting records matching this Cell
                    var cellAlarmQuery = qf.CellAlarmSetting.Where(CellAlarmSettingFields.CellId == entity.CellId);
                    var cellAlarmSettings = adapter.FetchQuery(cellAlarmQuery);

                    //AreaShift records matching this Cell’s Area
                    var areaShiftQuery = qf.AreaShift.Where(AreaShiftFields.AreaId == entity.AreaId).AndWhere(AreaShiftFields.Enabled == true);
                    var areaShifts = adapter.FetchQuery(areaShiftQuery);

                    //CellAlarmSetting records matching this Cell
                    var alarm_settings_query = qf.AlarmSetting.Where(AlarmSettingFields.AreaId == entity.AreaId);
                    var alarm_settings = adapter.FetchQuery(alarm_settings_query);

                    //RollupDefinition records for this Cell’s Area
                    var rollupDefQuery = qf.RollupDefinition.Where(RollupDefinitionFields.AreaId == entity.AreaId);
                    var rollupDefinitions = adapter.FetchQuery(rollupDefQuery);

                    //ReasonCode records for this Cell’s Area
                    var reasonCodeQuery = qf.ReasonCode.Where(ReasonCodeFields.AreaId == entity.AreaId);
                    var reasonCodes = adapter.FetchQuery(reasonCodeQuery);

                    //LaunchAPplication records for this Cell’s Area
                    var launchAppQuery = qf.LaunchApplication.Where(LaunchApplicationFields.AreaId == entity.AreaId).AndWhere(LaunchApplicationFields.Enabled == true);
                    var launchApplications = adapter.FetchQuery(launchAppQuery);

                    var operation_qry = qf.Operation;
                    var operations = adapter.FetchQuery(operation_qry);

                    //ProductionPlan records for this Cell’s Area
                    var productionPlanQuery = qf.ProductionPlan.Where(ProductionPlanFields.CellId == entity.CellId).AndWhere(ProductionPlanFields.Closed == false).AndWhere(ProductionPlanFields.Enabled == true);
                    var production_plans = adapter.FetchQuery(productionPlanQuery);
                    var product_ids = new List<int>();
                    foreach (ProductionPlanEntity ppe in production_plans)
                    {
                        product_ids.Add(ppe.ProductId);
                    }

                    //Product records for this Cell’s Area
                    var productQuery = qf.Product.Where(ProductFields.ProductId.In(product_ids));
                    var products = adapter.FetchQuery(productQuery);

                    // ProductOperationTime records for this Cell
                    var pot_qry = qf.ProductOperationTime
                        .From(QueryTarget.LeftJoin(qf.ProductionPlan).On((ProductionPlanFields.ProductId == ProductOperationTimeFields.ProductId)
                                                                         .And(ProductionPlanFields.OperationId == ProductOperationTimeFields.OperationId)
                                                                         .And(ProductionPlanFields.OperationPass == ProductOperationTimeFields.OperationPass))
                        )
                        .Where(ProductionPlanFields.CellId == entity.CellId)
                        .AndWhere(ProductionPlanFields.Closed == false)
                        .AndWhere(ProductionPlanFields.Enabled == true);
                    var product_operation_times = adapter.FetchQuery(pot_qry);

                    //Operator: Send down to the client TimeStamp = 0, and Enabled = Operator.Active
                    var operatorQuery = qf.Operator.Where(OperatorFields.AreaId == entity.AreaId).AndWhere(OperatorFields.Active == true);
                    var operators = adapter.FetchQuery(operatorQuery);

                    var operator_auth_qry = qf.OperatorAuth
                        .From(QueryTarget.InnerJoin(qf.Operator).On(OperatorFields.OperatorId == OperatorAuthFields.OperatorId))
                        .Where(OperatorFields.AreaId == entity.AreaId)
                        .AndWhere(OperatorFields.Active == true);
                    var operator_auths = adapter.FetchQuery(operator_auth_qry);

                    //HoseSpec: Send down to the client TimeStamp = 0, and Enabled = HoseSpec.Active
                    var hoseSpecQuery = qf.HoseSpec.Where(HoseSpecFields.AreaId == entity.AreaId);
                    var hoseSpecs = adapter.FetchQuery(hoseSpecQuery);

                    //FractionalInches: Send down to the client TimeStamp = 0, and Enabled = FractionalInches.Active
                    var fractionalInchesQuery = qf.FractionalInch;
                    var fractionalInches = adapter.FetchQuery(fractionalInchesQuery);
                    #endregion

                    #region Convert to DataContract for transferring
                    //Get all data need to sync
                    result.Cell = new CellItem
                    {
                        CellId = entity.CellId,
                        AreaId = entity.AreaId,
                        CellName = entity.CellName,
                        Password = newPassword,
                        Assigned = entity.Assigned,
                        Operators = entity.Operators,
                        Description = entity.CDescription,
                        Enabled = entity.CEnabled,
                        TimeStamp = entity.CTimeStamp,
                    };

                    result.Area = new AreaItem
                    {
                        AreaId = entity.AreaId,
                        PlantId = entity.PlantId,
                        AreaName = entity.AreaName,
                        ContinuousProcess = entity.ContinuousProcess,
                        GoodReasonCodeId = entity.GoodReasonCodeId,
                        ReworkReasonCodeId = entity.ReworkReasonCodeId,
                        ScrapReasonCodeId = entity.ScrapReasonCodeId,
                        ShiftStartReasonCodeId = entity.ShiftStartReasonCodeId,
                        CloseWorkOrderReasonCodeId = entity.CloseWorkOrderReasonCodeId,
                        NoWorkOrdersReasonCodeId = entity.NoWorkOrdersReasonCodeId,
                        WeekStartDay = entity.WeekStartDay,
                        MonthStartDay = entity.MonthStartDay,
                        ProductionMeterWidth = entity.ProductionMeterWidth,
                        ProductionMeterLabelFreq = entity.ProductionMeterLabelFreq,
                        PlannedReasonCodeId = entity.PlannedReasonCodeId,
                        ProductionGoal = entity.ProductionGoal,
                        Description = entity.ADescription,
                        Enabled = entity.AEnabled,
                        TimeStamp = entity.ATimeStamp,
                    };

                    result.Plant = new PlantItem
                    {
                        PlantId = entity.PlantId,
                        PlantName = entity.PlantName,
                        Description = entity.PDescription,
                        DateFormat = entity.PDateFormat,
                        Enabled = entity.PEnabled,
                        TimeStamp = entity.PTimeStamp,
                    };

                    if (cellAlarmSettings != null)
                    {
                        result.CellAlarmSettings = new List<CellAlarmSettingItem>();
                        foreach (CellAlarmSettingEntity e in cellAlarmSettings)
                        {
                            result.CellAlarmSettings.Add(new CellAlarmSettingItem
                            {
                                CellAlarmSettingId = e.CellAlarmSettingId,
                                CellId = e.CellId,
                                Color = e.Color,
                                FontColor = e.FontColor,
                                MinPercentage100Bad = e.MinPercentage100Bad,
                                MinPercentage100Good = e.MinPercentage100Good,
                                TimeStamp = e.TimeStamp,
                            });
                        }
                    }

                    if (areaShifts != null)
                    {
                        result.AreaShifts = new List<AreaShiftItem>();
                        foreach (AreaShiftEntity e in areaShifts)
                        {
                            result.AreaShifts.Add(new AreaShiftItem
                            {
                                AreaShiftId = e.AreaShiftId,
                                AreaId = e.AreaId,
                                Description = e.Description,
                                StartTime = e.StartTime,
                                EndTime = e.EndTime,
                                Enabled = e.Enabled,
                                Hidden = e.Hidden,
                                TimeStamp = e.TimeStamp,
                            });
                        }
                    }

                    if (alarm_settings != null)
                    {
                        result.AlarmSettings = new List<AlarmSettingItem>();
                        foreach (AlarmSettingEntity e in alarm_settings)
                        {
                            result.AlarmSettings.Add(new AlarmSettingItem
                            {
                                AlarmSettingId = e.AlarmSettingId,
                                AreaId = e.AreaId,
                                FontColor = e.FontColor,
                                Color = e.Color,
                                MinPercentageBad = e.MinPercentage100Bad,
                                MinPercentageGood = e.MinPercentage100Good,
                                TimeStamp = e.TimeStamp,
                            });
                        }
                    }

                    if (rollupDefinitions != null)
                    {
                        result.RollupDefinitions = new List<RollupDefinitionItem>();
                        foreach (RollupDefinitionEntity e in rollupDefinitions)
                        {
                            result.RollupDefinitions.Add(new RollupDefinitionItem
                            {
                                RollupDefinitionId = e.RollupDefinitionId,
                                AreaId = e.AreaId,
                                Description = e.Description,
                                Color = e.Color,
                                FontColor = e.FontColor,
                                SortOrder = e.SortOrder,
                                FlashingTimeout = e.FlashingTimeout,
                                TimeStamp = e.TimeStamp,
                            });
                        }
                    }

                    if (reasonCodes != null)
                    {
                        result.ReasonCodes = new List<ReasonCodeItem>();
                        foreach (ReasonCodeEntity e in reasonCodes)
                        {
                            result.ReasonCodes.Add(new ReasonCodeItem
                            {
                                ReasonCodeId = e.ReasonCodeId,
                                AreaId = e.AreaId,
                                Description = e.Description,
                                Level = e.Level,
                                RollupDefinitionId = e.RollupDefinitionId,
                                ParentId = e.ParentId,
                                LinkId = e.LinkId,
                                IgnoreVisiBoxEvents = e.IgnoreVisiBoxEvents,
                                Category = (ReasonCodeItem.ReasonCodeCategory)e.Category,
                                ShopClockEvent = (ReasonCodeItem.ShopClockEventEnum)e.ShopClockEvent,
                                HideChildren = e.HideChildren,
                                FlashDelay = e.FlashDelay,
                                DisplayInDowntimeChart = e.DisplayInDowntimeChart,
                                IgnoreInOeeCalc = e.IgnoreInOeeCalc,
                                IgnoreInWaitingCalc = e.IgnoreInWaitingCalc,
                                TimeStamp = e.TimeStamp,
                            });
                        }
                    }

                    if (launchApplications != null)
                    {
                        result.LaunchApplications = new List<LaunchApplicationItem>();
                        foreach (LaunchApplicationEntity e in launchApplications)
                        {
                            result.LaunchApplications.Add(new LaunchApplicationItem
                            {
                                LaunchApplicationId = e.LaunchApplicationId,
                                AreaId = e.AreaId,
                                Description = e.Description,
                                Enabled = e.Enabled,
                                Application = e.Application,
                                Arguments = e.Arguments,
                                SortOrder = e.SortOrder,
                                TimeStamp = e.TimeStamp,
                            });
                        }
                    }

                    if (operators != null)
                    {
                        result.Operators = new List<OperatorItem>();
                        foreach (OperatorEntity e in operators)
                        {
                            result.Operators.Add(new OperatorItem
                            {
                                OperatorId = e.OperatorId,
                                AreaId = e.AreaId,
                                EmployeeCode = e.EmployeeCode,
                                FirstName = e.FirstName,
                                LastName = e.LastName,
                                Active = e.Active,
                                TimeStamp = e.TimeStamp,
                            });
                        }
                    }

                    if (operator_auths != null)
                    {
                        result.OperatorAuths = new List<OperatorAuthItem>();
                        foreach (OperatorAuthEntity e in operator_auths)
                        {
                            result.OperatorAuths.Add(new OperatorAuthItem
                            {
                                OperatorId = e.OperatorId,
                                OperatorAuthId = e.OperatorAuthId,
                                OperationId = e.OperationId
                            });
                        }
                    }

                    if (operations != null)
                    {
                        result.Operations = new List<OperationItem>();
                        foreach (OperationEntity e in operations)
                        {
                            result.Operations.Add(new OperationItem
                            {
                                OperationId = e.OperationId,
                                Description = e.Description,
                                Enabled = e.Enabled,
                                TimeStamp = e.TimeStamp
                            });
                        }
                    }

                    if (products != null)
                    {
                        result.Products = new List<ProductItem>();
                        foreach (ProductEntity e in products)
                        {
                            result.Products.Add(new ProductItem
                            {
                                ProductId = e.ProductId,
                                Sku = e.Sku,
                                Description = e.Description,
                                Revision = e.Revision,
                                Enabled = e.Enabled,
                                TimeStamp = e.TimeStamp,
                            });
                        }
                    }

                    if (product_operation_times != null)
                    {
                        result.ProductOperationTimes = new List<ProductOperationTimeItem>();
                        foreach (ProductOperationTimeEntity e in product_operation_times)
                        {
                            result.ProductOperationTimes.Add(new ProductOperationTimeItem
                            {
                                ProductOperationTimeId = e.ProductOperationTimeId,
                                ProductId = e.ProductId,
                                OperationId = e.OperationId,
                                OperationPass = e.OperationPass,
                                PartTime = e.PartTime,
                                SetupTime = e.SetupTime,
                                CycleTime = e.CycleTime,
                                LoadUnloadTime = e.LoadUnloadTime,
                                TimeStamp = e.TimeStamp
                            });
                        }
                    }

                    if (production_plans != null)
                    {
                        result.ProductionPlans = new List<ProductionPlanItem>();
                        foreach (ProductionPlanEntity e in production_plans)
                        {
                            result.ProductionPlans.Add(new ProductionPlanItem
                            {
                                ProductionPlanId = e.ProductionPlanId,
                                CellId = e.CellId,
                                ProductId = e.ProductId,
                                WorkOrder = e.WorkOrder,
                                OperationId = e.OperationId,
                                OperationPass = e.OperationPass,
                                StationId = e.StationId,
                                DueDate = e.DueDate,
                                Planned = e.Planned,
                                Actual = e.Actual,
                                ActualDate = e.ActualDate,
                                SortOrder = e.SortOrder,
                                Closed = e.Closed,
                                Enabled = e.Enabled,
                                TimeStamp = e.TimeStamp,
                            });
                        }
                    }

                    if (hoseSpecs != null)
                    {
                        result.HoseSpecs = new List<HoseSpecItem>();
                        foreach (HoseSpecEntity e in hoseSpecs)
                        {
                            result.HoseSpecs.Add(new HoseSpecItem
                            {
                                HoseSpecId = e.HoseSpecId,
                                AreaId = e.AreaId,
                                Spec = e.Spec,
                                Size = e.Size,
                                FtPerMin = e.FtPerMin,
                                FtPerMinRb2 = e.FtPerMinRb2,
                                FtPerMinAlt = e.FtPerMinAlt,
                                TimeStamp = e.TimeStamp,
                            });
                        }
                    }

                    if (fractionalInches != null)
                    {
                        result.FractionalInches = new List<FractionalInchItem>();
                        foreach (FractionalInchEntity e in fractionalInches)
                        {
                            result.FractionalInches.Add(new FractionalInchItem
                            {
                                FractionalInchesId = e.FractionalInchesId,
                                Description = e.Description,
                                Value = e.Value,
                                TimeStamp = e.TimeStamp,
                            });
                        }
                    }

                    if (table_data_changes != null)
                    {
                        result.TableDataChanges = new List<TableDataChangeItem>();
                        foreach (TableDataChangeEntity e in table_data_changes)
                        {
                            result.TableDataChanges.Add(new TableDataChangeItem
                            {
                                TableDataChangeId = e.TableDataChangeId,
                                TableName = e.TableName,
                                AreaId = e.AreaId,
                                CellId = e.CellId,
                                LastChanged = e.LastChanged,
                                TimeStamp = e.TimeStamp,
                            });
                        }
                    }
                    #endregion

                    adapter.Commit();
                    return result;
                }
                catch (Exception e)
                {
                    adapter.Rollback();
                    FileLog.Error("VerifyCellAndGetServerData() - ", e);
                    return new ConfigureResponse { Success = false, Error = BusinessLogicError.ConfigureFailed, };
                }
            }
        }


        public ConfigureResponse SyncDataFromServerToClient(ConfigureRequest request)
        {
            #region Declaration
            var result = new ConfigureResponse() { Success = true, };

            var qf = new QueryFactory();
            var cell_qry = qf.Cell.Where(CellFields.Password == request.Password & CellFields.CellId == request.CellId);
            #endregion

            using (var adapter = new DataAccessAdapter())
            {
                try
                {
                    adapter.StartTransaction(IsolationLevel.ReadCommitted, "ConfigureTransaction");

                    #region Get data from DB

                    //verify CellID and Cell.Password
                    var cell = adapter.FetchFirst(cell_qry);
                    if (cell == null)
                     return new ConfigureResponse { Success = false, Error = BusinessLogicError.InvalidCellPassword, };
                    
                    var tdc_qry = qf.TableDataChange
                        .Where(TableDataChangeFields.CellId == cell.CellId)
                        .OrWhere((TableDataChangeFields.CellId.IsNull()).And(TableDataChangeFields.AreaId == cell.AreaId));
                    var table_data_changes = adapter.FetchQuery(tdc_qry);

                    var tdc_timestamps = new List<byte[]>();
                    foreach (TableDataChangeEntity tdc in table_data_changes)
                    {
                        tdc_timestamps.Add(tdc.TimeStamp);
                    }

                    EntityCollection<CellAlarmSettingEntity> cell_alarm_settings = null;
                    EntityCollection<AreaShiftEntity> area_shifts = null;
                    EntityCollection<AlarmSettingEntity> alarm_settings = null;
                    EntityCollection<RollupDefinitionEntity> rollup_definitions = null;
                    EntityCollection<ReasonCodeEntity> reason_codes = null;
                    EntityCollection<LaunchApplicationEntity> launch_applications = null;
                    EntityCollection<ProductionPlanEntity> production_plans = null;
                    EntityCollection<ProductEntity> products = null;
                    EntityCollection<OperatorEntity> operators = null;
                    EntityCollection<OperatorAuthEntity> operator_auths = null;
                    EntityCollection<OperationEntity> operations = null;
                    EntityCollection<HoseSpecEntity> hose_specs = null;
                    EntityCollection<FractionalInchEntity> fractional_inches = null;

                    if (request.TableChanges != null)
                    {
                        foreach (var tdci in request.TableChanges)
                        {
                            if (!tdc_timestamps.Any(x => x.SequenceEqual(tdci.TimeStamp)))
                            {
                                switch (tdci.TableName)
                                {
                                    case "ReasonCode":
                                        //ReasonCode records for this Cell’s Area
                                        var reason_code_qry = qf.ReasonCode.Where(ReasonCodeFields.AreaId == cell.AreaId);
                                        reason_codes = (EntityCollection<ReasonCodeEntity>)adapter.FetchQuery(reason_code_qry);
                                        break;

                                    case "RollupDefinition":
                                        //RollupDefinition records for this Cell’s Area
                                        var rollup_definition_qry = qf.RollupDefinition.Where(RollupDefinitionFields.AreaId == cell.AreaId);
                                        rollup_definitions = (EntityCollection<RollupDefinitionEntity>)adapter.FetchQuery(rollup_definition_qry);
                                        break;

                                    case "Operator":
                                        var operator_qry = qf.Operator.Where(OperatorFields.AreaId == cell.AreaId).AndWhere(OperatorFields.Active == true);
                                        operators = (EntityCollection<OperatorEntity>)adapter.FetchQuery(operator_qry);
                                        break;

                                    case "OperatorAuth":
                                        // FIX THIS var operator_auth_qry = qf.OperatorAuth.Where(OperatorFields.AreaId == cell.AreaId);
                                        //operator_auths = (EntityCollection<OperatorAuthEntity>)adapter.FetchQuery(operator_auth_qry);
                                        break;

                                    case "Operation":
                                        var operation_qry = qf.Operation;
                                        operations = (EntityCollection<OperationEntity>)adapter.FetchQuery(operation_qry);
                                        break;

                                    default:
                                        // TO DO - add more tables
                                        break;

                                }
                            }
                        }
                    }

                    // ProductionPlan records for this Cell’s Area
                    var production_plan_qry = qf.ProductionPlan.Where(ProductionPlanFields.CellId == cell.CellId).AndWhere(ProductionPlanFields.Closed == false).AndWhere(ProductionPlanFields.Enabled == true);
                    production_plans = (EntityCollection<ProductionPlanEntity>)adapter.FetchQuery(production_plan_qry);
                    var product_ids = new List<int>();
                    foreach (ProductionPlanEntity ppe in production_plans)
                    {
                        product_ids.Add(ppe.ProductId);
                    }

                    // Product records for this Cell’s Area
                    var product_qry = qf.Product.Where(ProductFields.ProductId.In(product_ids));
                    products = (EntityCollection<ProductEntity>)adapter.FetchQuery(product_qry);

                    // ProductOperationTime records for this Cell
                    var pot_qry = qf.ProductOperationTime
                        .From(QueryTarget.LeftJoin(qf.ProductionPlan).On((ProductionPlanFields.ProductId == ProductOperationTimeFields.ProductId)
                                                                         .And(ProductionPlanFields.OperationId == ProductOperationTimeFields.OperationId)
                                                                         .And(ProductionPlanFields.OperationPass == ProductOperationTimeFields.OperationPass))
                        )
                        .Where(ProductionPlanFields.CellId == cell.CellId)
                        .AndWhere(ProductionPlanFields.Closed == false)
                        .AndWhere(ProductionPlanFields.Enabled == true);
                    var product_operation_times = adapter.FetchQuery(pot_qry);

                    #endregion

                    #region Convert to DataContract for transferring
                    //Get all data need to sync

                    result.Cell = new CellItem
                    {
                        CellId = cell.CellId,
                        AreaId = cell.AreaId,
                        CellName = cell.CellName,
                        Password = cell.Password,
                        Assigned = cell.Assigned,
                        Operators = cell.Operators,
                        Description = cell.Description,
                        Enabled = cell.Enabled,
                        TimeStamp = cell.TimeStamp,
                    };

                    if (cell_alarm_settings != null)
                    {
                        result.CellAlarmSettings = new List<CellAlarmSettingItem>();
                        foreach (CellAlarmSettingEntity e in cell_alarm_settings)
                        {
                            result.CellAlarmSettings.Add(new CellAlarmSettingItem
                            {
                                CellAlarmSettingId = e.CellAlarmSettingId,
                                CellId = e.CellId,
                                Color = e.Color,
                                FontColor = e.FontColor,
                                MinPercentage100Bad = e.MinPercentage100Bad,
                                MinPercentage100Good = e.MinPercentage100Good,
                                TimeStamp = e.TimeStamp,
                            });
                        }
                    }

                    if (area_shifts != null)
                    {
                        result.AreaShifts = new List<AreaShiftItem>();
                        foreach (AreaShiftEntity e in area_shifts)
                        {
                            result.AreaShifts.Add(new AreaShiftItem
                            {
                                AreaShiftId = e.AreaShiftId,
                                AreaId = e.AreaId,
                                Description = e.Description,
                                StartTime = e.StartTime,
                                EndTime = e.EndTime,
                                Enabled = e.Enabled,
                                Hidden = e.Hidden,
                                TimeStamp = e.TimeStamp,
                            });
                        }
                    }

                    if (alarm_settings != null)
                    {
                        result.AlarmSettings = new List<AlarmSettingItem>();
                        foreach (AlarmSettingEntity e in alarm_settings)
                        {
                            result.AlarmSettings.Add(new AlarmSettingItem
                            {
                                AlarmSettingId = e.AlarmSettingId,
                                AreaId = e.AreaId,
                                FontColor = e.FontColor,
                                Color = e.Color,
                                MinPercentageBad = e.MinPercentage100Bad,
                                MinPercentageGood = e.MinPercentage100Good,
                                TimeStamp = e.TimeStamp,
                            });
                        }
                    }

                    if (rollup_definitions != null)
                    {
                        result.RollupDefinitions = new List<RollupDefinitionItem>();
                        foreach (RollupDefinitionEntity e in rollup_definitions)
                        {
                            result.RollupDefinitions.Add(new RollupDefinitionItem
                            {
                                RollupDefinitionId = e.RollupDefinitionId,
                                AreaId = e.AreaId,
                                Description = e.Description,
                                Color = e.Color,
                                FontColor = e.FontColor,
                                SortOrder = e.SortOrder,
                                FlashingTimeout = e.FlashingTimeout,
                                TimeStamp = e.TimeStamp,
                            });
                        }
                    }

                    if (reason_codes != null)
                    {
                        result.ReasonCodes = new List<ReasonCodeItem>();
                        foreach (ReasonCodeEntity e in reason_codes)
                        {
                            result.ReasonCodes.Add(new ReasonCodeItem
                            {
                                ReasonCodeId = e.ReasonCodeId,
                                AreaId = e.AreaId,
                                Description = e.Description,
                                Level = e.Level,
                                RollupDefinitionId = e.RollupDefinitionId,
                                ParentId = e.ParentId,
                                LinkId = e.LinkId,
                                IgnoreVisiBoxEvents = e.IgnoreVisiBoxEvents,
                                Category = (ReasonCodeItem.ReasonCodeCategory)e.Category,
                                ShopClockEvent = (ReasonCodeItem.ShopClockEventEnum)e.ShopClockEvent,
                                HideChildren = e.HideChildren,
                                FlashDelay = e.FlashDelay,
                                DisplayInDowntimeChart = e.DisplayInDowntimeChart,
                                IgnoreInOeeCalc = e.IgnoreInOeeCalc,
                                IgnoreInWaitingCalc = e.IgnoreInWaitingCalc,
                                TimeStamp = e.TimeStamp,
                            });
                        }
                    }

                    if (launch_applications != null)
                    {
                        result.LaunchApplications = new List<LaunchApplicationItem>();
                        foreach (LaunchApplicationEntity e in launch_applications)
                        {
                            result.LaunchApplications.Add(new LaunchApplicationItem
                            {
                                LaunchApplicationId = e.LaunchApplicationId,
                                AreaId = e.AreaId,
                                Description = e.Description,
                                Enabled = e.Enabled,
                                Application = e.Application,
                                Arguments = e.Arguments,
                                SortOrder = e.SortOrder,
                                TimeStamp = e.TimeStamp,
                            });
                        }
                    }

                    if (operators != null)
                    {
                        result.Operators = new List<OperatorItem>();
                        foreach (OperatorEntity e in operators)
                        {
                            result.Operators.Add(new OperatorItem
                            {
                                OperatorId = e.OperatorId,
                                AreaId = e.AreaId,
                                EmployeeCode = e.EmployeeCode,
                                FirstName = e.FirstName,
                                LastName = e.LastName,
                                Active = e.Active,
                                TimeStamp = e.TimeStamp,
                            });
                        }
                    }

                    if (operator_auths != null)
                    {
                        result.OperatorAuths = new List<OperatorAuthItem>();
                        foreach (OperatorAuthEntity e in operator_auths)
                        {
                            result.OperatorAuths.Add(new OperatorAuthItem
                            {
                                OperatorAuthId = e.OperatorAuthId,
                                OperatorId = e.OperatorId,
                                OperationId = e.OperationId,
                            });
                        }
                    }

                    if (operations != null)
                    {
                        result.Operations = new List<OperationItem>();
                        foreach (OperationEntity e in operations)
                        {
                            result.Operations.Add(new OperationItem
                            {
                                OperationId = e.OperationId,
                                Description = e.Description,
                                Enabled = e.Enabled,
                                TimeStamp = e.TimeStamp
                            });
                        }
                    }


                    if (products != null)
                    {
                        result.Products = new List<ProductItem>();
                        foreach (ProductEntity e in products)
                        {
                            result.Products.Add(new ProductItem
                            {
                                ProductId = e.ProductId,
                                Sku = e.Sku,
                                Description = e.Description,
                                Revision = e.Revision,
                                Enabled = e.Enabled,
                                TimeStamp = e.TimeStamp,
                            });
                        }
                    }

                    if (product_operation_times != null)
                    {
                        result.ProductOperationTimes = new List<ProductOperationTimeItem>();
                        foreach (ProductOperationTimeEntity e in product_operation_times)
                        {
                            result.ProductOperationTimes.Add(new ProductOperationTimeItem
                            {
                                ProductOperationTimeId = e.ProductOperationTimeId,
                                ProductId = e.ProductId,
                                OperationId = e.OperationId,
                                OperationPass = e.OperationPass,
                                Rate = e.Rate,
                                PartTime = e.PartTime,
                                SetupTime = e.SetupTime,
                                CycleTime = e.CycleTime,
                                LoadUnloadTime = e.LoadUnloadTime,
                                TimeStamp = e.TimeStamp
                            });
                        }
                    }

                    if (production_plans != null)
                    {
                        result.ProductionPlans = new List<ProductionPlanItem>();
                        foreach (ProductionPlanEntity e in production_plans)
                        {
                            result.ProductionPlans.Add(new ProductionPlanItem
                            {
                                ProductionPlanId = e.ProductionPlanId,
                                CellId = e.CellId,
                                ProductId = e.ProductId,
                                WorkOrder = e.WorkOrder,
                                OperationId = e.OperationId,
                                OperationPass = e.OperationPass,
                                StationId = e.StationId,
                                DueDate = e.DueDate,
                                Planned = e.Planned,
                                Actual = e.Actual,
                                ActualDate = e.ActualDate,
                                SortOrder = e.SortOrder,
                                Closed = e.Closed,
                                Enabled = e.Enabled,
                                TimeStamp = e.TimeStamp,
                            });
                        }
                    }

                    if (hose_specs != null)
                    {
                        result.HoseSpecs = new List<HoseSpecItem>();
                        foreach (HoseSpecEntity e in hose_specs)
                        {
                            result.HoseSpecs.Add(new HoseSpecItem
                            {
                                HoseSpecId = e.HoseSpecId,
                                AreaId = e.AreaId,
                                Spec = e.Spec,
                                Size = e.Size,
                                FtPerMin = e.FtPerMin,
                                FtPerMinRb2 = e.FtPerMinRb2,
                                FtPerMinAlt = e.FtPerMinAlt,
                                TimeStamp = e.TimeStamp,
                            });
                        }
                    }

                    if (fractional_inches != null)
                    {
                        result.FractionalInches = new List<FractionalInchItem>();
                        foreach (FractionalInchEntity e in fractional_inches)
                        {
                            result.FractionalInches.Add(new FractionalInchItem
                            {
                                FractionalInchesId = e.FractionalInchesId,
                                Description = e.Description,
                                Value = e.Value,
                                TimeStamp = e.TimeStamp,
                            });
                        }
                    }

                    if (table_data_changes != null)
                    {
                        result.TableDataChanges = new List<TableDataChangeItem>();
                        foreach (TableDataChangeEntity e in table_data_changes)
                        {
                            result.TableDataChanges.Add(new TableDataChangeItem
                            {
                                TableDataChangeId = e.TableDataChangeId,
                                TableName = e.TableName,
                                AreaId = e.AreaId,
                                CellId = e.CellId,
                                LastChanged = e.LastChanged,
                                TimeStamp = e.TimeStamp,
                            });
                        }
                    }
                    #endregion

                    adapter.Commit();
                    return result;
                }
                catch (Exception ex)
                {
                    adapter.Rollback();
                    FileLog.Error("SyncDataFromServerToClient() - " + request.CellId.ToString() + " - ", ex);
                    FileLog.Error("SyncDataFromServerToClient() - ", ex.InnerException);
                    return new ConfigureResponse { Success = false, Error = BusinessLogicError.ConfigureFailed, };
                }
            }
        }

        public SyncDataFromClientResponse SyncDataFromClientToServer(SyncDataFromClientRequest request)
        {
            var result = new SyncDataFromClientResponse() { Success = true, };
            var qf = new QueryFactory();
            var cellQuery = qf.Cell.Where(CellFields.Password == request.Password & CellFields.CellId == request.CellId);

            var updateCellShiftIds = request.LocalData.CellShifts.Select(t => t.CellShiftId).Where(t => t != 0).ToList();
            var updateBraiderProductIds = request.LocalData.BraiderProducts.Select(t => t.BraiderProductId).Where(t => t != 0);
            var updateProductionHistoryDowntimeEventIds = request.LocalData.ProductionHistoryDowntimeEvents.Select(t => t.ProductionHistoryDowntimeEventId).Where(t => t != 0);

            string stage = "000";

            using (var adapter = new DataAccessAdapter())
            {
                try
                {
                    adapter.StartTransaction(IsolationLevel.ReadCommitted, "ConfigureTransaction");

                    //verify CellID and Cell.Password
                    var cellEntity = ((EntityCollection<CellEntity>)adapter.FetchQuery(cellQuery)).FirstOrDefault();
                    if (cellEntity == null)
                        return new SyncDataFromClientResponse { Success = false, Error = BusinessLogicError.InvalidCellPassword, };

                    #region For all records where ServerID is NOT defined, insert new records into the table; otherwise update records;  ServerId is returned back to the clien

                    stage = "100";

                    int id;

                    #region CellShift
                    var cell_shifts_to_save = new EntityCollection<CellShiftEntity>();
                    foreach (var item in request.LocalData.CellShifts)
                    {
                        id = item.CellShiftId;
                        if (id == 0)
                        {
                            // Maybe the client end of the sync failed last time
                            var qry = qf.Create()
                            .Select(() => new
                                {
                                    Id = CellShiftFields.CellShiftId.Source("cs").ToValue<int>()
                                })
                                .From(qf.CellShift.As("cs"))
                                .Where(CellShiftFields.ClientId.Source("cs") == item.ClientId)
                                .AndWhere(CellShiftFields.CellId.Source("cs") == item.CellId)
                                .AndWhere(CellShiftFields.StartTime.Source("cs") == item.StartTime);
                            var val = adapter.FetchQuery(qry).FirstOrDefault();
                            if (val != null)
                                id = val.Id;
                        }

                        cell_shifts_to_save.Add(new CellShiftEntity
                            {
                                CellShiftId = id,
                                ClientId = item.ClientId,
                                AreaShiftId = item.AreaShiftId,
                                CellId = item.CellId,
                                StartTime = item.StartTime,
                                EndTime = item.EndTime,
                                IsNew = (id == 0)
                            });
                    }
                    adapter.SaveEntityCollection(cell_shifts_to_save, true, false);

                    foreach (var e in cell_shifts_to_save)
                    {
                        var item = request.LocalData.CellShifts.FirstOrDefault(t => t.ClientId == e.ClientId);
                        if (item != null)
                            item.CellShiftId = e.CellShiftId;

                        foreach (var item2 in request.LocalData.ProductionHistories.Where(t => t.CellShiftId == 0 && t.CellShiftClientId == e.ClientId))
                            item2.CellShiftId = e.CellShiftId;
                    }
                    #endregion

                    #region BraiderProduct
                    var braider_products_to_save = new EntityCollection<BraiderProductEntity>();
                    foreach (var item in request.LocalData.BraiderProducts)
                    {
                        id = item.BraiderProductId;
                        if (id == 0)
                        {
                            // Maybe the client end of the sync failed last time
                            var qry = qf.Create()
                            .Select(() => new
                            {
                                Id = BraiderProductFields.BraiderProductId.Source("bp").ToValue<int>()
                            })
                                .From(qf.BraiderProduct.As("bp"))
                                .Where(BraiderProductFields.ClientId.Source("bp") == item.ClientId)
                                .AndWhere(BraiderProductFields.BraiderNumber.Source("bp") == item.BraiderNumber)
                                .AndWhere(BraiderProductFields.OperatorId.Source("cs") == item.OperatorId);
                            var val = adapter.FetchQuery(qry).FirstOrDefault();
                            if (val != null)
                                id = val.Id;
                        }
                        braider_products_to_save.Add(new BraiderProductEntity
                        {
                            BraiderProductId = id,
                            ClientId = item.ClientId,
                            OperatorId = item.OperatorId,
                            BraiderNumber = item.BraiderNumber,
                            HoseSpec = item.HoseSpec,
                            HoseSize = item.HoseSize,
                            HoseCount = item.HoseCount,
                            BraiderType = item.BraiderType,
                            FeetPerMinute = item.FeetPerMinute,
                            CarrierCount = item.CarrierCount,
                            DeckCount = item.DeckCount,
                            Split = item.Split,
                            IsNew = (id == 0)
                        });
                    }
                    adapter.SaveEntityCollection(braider_products_to_save, true, false);

                    foreach (var e in braider_products_to_save)
                    {
                        var item = request.LocalData.BraiderProducts.FirstOrDefault(t => t.ClientId == e.ClientId && t.BraiderProductId == 0);
                        if (item != null)
                            item.BraiderProductId = e.BraiderProductId;

                        foreach (var item2 in request.LocalData.ProductionHistories.Where(t => t.BraiderProductId == e.ClientId))
                            item2.BraiderProductId = e.BraiderProductId;

                    }
                    #endregion

                    #region ProductionHistory
                    var production_histories_to_save = new EntityCollection<ProductionHistoryEntity>();
                    var production_plan_ids = new List<int>();
                    int prev_production_plan_id = -1;
                    foreach (var item in request.LocalData.ProductionHistories)
                    {
                        id = item.ProductionHistoryId;
                        if (id == 0)
                        {
                            // Maybe the client end of the sync failed last time
                            var qry = qf.Create()
                                .Select(() => new
                                {
                                    Id = ProductionHistoryFields.ProductionHistoryId.Source("ph").ToValue<int>()
                                })
                                .From(qf.ProductionHistory.As("ph"))
                                .Where(ProductionHistoryFields.ClientId.Source("ph") == item.ClientId)
                                .AndWhere(ProductionHistoryFields.CellShiftId.Source("ph") == item.CellShiftId);
                            var val = adapter.FetchFirst(qry);
                            if (val != null)
                                id = val.Id;
                        }
                        production_histories_to_save.Add(new ProductionHistoryEntity
                        {
                            ClientId = item.ClientId,
                            ProductionHistoryId = id,
                            CellShiftId = item.CellShiftId,
                            ReasonCodeId = item.ReasonCodeId,
                            ProductionPlanId = item.ProductionPlanId,
                            BraiderProductId = item.BraiderProductId,
                            Operators = item.Operators,
                            WorkContent = item.WorkContent,
                            StartTime = item.StartTime,
                            EndTime = item.EndTime,
                            DowntimeAckTime = item.DowntimeAckTime,
                            VisiBoxKey = item.VisiBoxKey,
                            IsNew = (id == 0)
                        });

                        if (item.ProductionPlanId.HasValue && prev_production_plan_id != item.ProductionPlanId.Value)
                        {
                            prev_production_plan_id = item.ProductionPlanId.Value;
                            if (!production_plan_ids.Contains(prev_production_plan_id))
                                production_plan_ids.Add(prev_production_plan_id);
                        }
                    }
                    adapter.SaveEntityCollection(production_histories_to_save, true, false);

                    foreach (var e in production_histories_to_save)
                    {
                        var item = request.LocalData.ProductionHistories.FirstOrDefault(t => t.ClientId == e.ClientId && t.ProductionHistoryId == 0);
                        if (item != null)
                            item.ProductionHistoryId = e.ProductionHistoryId;

                        foreach (var item2 in request.LocalData.ProductionHistoryDowntimeEvents.Where(t => t.ProductionHistoryClientId == e.ClientId))
                            item2.ProductionHistoryServerId = e.ProductionHistoryId;
                    }
                    #endregion

                    #region ProductionHistoryDowntimeEvent
                    var production_history_downtime_events_to_save = new EntityCollection<ProductionHistoryDowntimeEventEntity>();
                    foreach (var item in request.LocalData.ProductionHistoryDowntimeEvents)
                    {
                        if (item.ProductionHistoryServerId.HasValue)
                        {
                            production_history_downtime_events_to_save.Add(new ProductionHistoryDowntimeEventEntity
                            {
                                ClientId = item.ClientId,
                                ProductionHistoryDowntimeEventId = 0,
                                ProductionHistoryId = item.ProductionHistoryServerId.Value,
                                ReasonCodeId = item.ReasonCodeId,
                                EventTime = item.EventTime,
                                VisiBoxKey = item.VisiBoxKey,
                            });
                        }
                        else
                        {
                            FileLog.Error("SyncDataFromClientToServer() - " + item.ClientId.ToString());
                        }
                    }
                    adapter.SaveEntityCollection(production_history_downtime_events_to_save, true, false);

                    foreach (var e in production_history_downtime_events_to_save)
                    {
                        var item = request.LocalData.ProductionHistoryDowntimeEvents.FirstOrDefault(t => t.ClientId == e.ClientId);
                        if (item == null) continue;

                        item.ProductionHistoryDowntimeEventId = e.ProductionHistoryDowntimeEventId;
                    }
                    #endregion

                    #endregion

                    stage = "300";

                    #region CellStatus: There is no need to deal with SyncStatus or ServerIDs
                    // There will only be one BraiderStatus record for each cell.  
                    // We always overwrite the data on the server with the data on the client.  
                    if (request.LocalData.CellStatus != null)
                    {
                        var qry = qf.CellStatus.Where(CellStatusFields.CellId == request.LocalData.CellStatus.CellId);
                        CellStatusEntity cell_status = adapter.FetchFirst(qry);
                        if (cell_status == null)
                            cell_status = new CellStatusEntity();

                        cell_status.CellId = request.LocalData.CellStatus.CellId;
                        cell_status.ReasonCodeId = request.LocalData.CellStatus.ReasonCodeId;
                        cell_status.Status = request.LocalData.CellStatus.Status;
                        cell_status.Offline = request.LocalData.CellStatus.Offline;
                        cell_status.EventTime = request.LocalData.CellStatus.EventTime;
                        cell_status.Flags = request.LocalData.CellStatus.Flags;
                        cell_status.LastSync = DateTime.Now;

                        if (cell_status.TimeStamp != request.LocalData.CellStatus.TimeStamp)
                            cell_status.TimeStamp = request.LocalData.CellStatus.TimeStamp;

                        adapter.SaveEntity(cell_status);
                    }

                    #endregion

                    result.LocalData = request.LocalData;

                    // Update ProductionPlan Actual
                    stage = "400";
                    foreach (var pp_id in production_plan_ids)
                    {
                        var pp = new ProductionPlanEntity(pp_id);
                        if (adapter.FetchEntity(pp))
                        {

                            var parts_created_qry = qf.Create()
                                .Select(() => new
                                {
                                    StartTime = ProductionHistoryFields.StartTime.ToValue<DateTime>(),
                                })
                                .From(qf.ProductionHistory
                                    .InnerJoin(qf.ReasonCode).On(ReasonCodeFields.ReasonCodeId == ProductionHistoryFields.ReasonCodeId)
                                    )
                                .Where(ProductionHistoryFields.ProductionPlanId == pp_id)
                                .AndWhere(ReasonCodeFields.Category == (int)ReasonCodeItem.ReasonCodeCategory.PartProduced)
                                .OrderBy(ProductionHistoryFields.StartTime.Descending());

                            pp.Actual = adapter.FetchScalar<int>(qf.Create().Select(parts_created_qry.CountRow()));
                            var when = adapter.FetchFirst(parts_created_qry);
                            if (when != null)
                                pp.ActualDate = when.StartTime;
                            else
                                pp.ActualDate = null;
                            adapter.SaveEntity(pp);

                        }
                    }

                    adapter.Commit();

                    //Send back to the client a list of ServerID, ClientID pairs for all records that were add or updated
                    return result;
                }
                catch (Exception e)
                {
                    adapter.Rollback();
                    FileLog.Error("SyncDataFromClientToServer() - " + stage + " - ", e);
                    return new SyncDataFromClientResponse { Success = false, Error = BusinessLogicError.SyncClientServerError, };
                }
            }
        }
    }
}
